﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace LightEngine
{
    namespace VisualTools
    {
        namespace WindowsFormsTools
        {
            public enum DrawType
            {
                Points = 0,
                Axis = 1,
                LeftMarkers = 2,
                RightMarkers = 3,
                AxisSigns = 4,
                XAxisTitle = 5,
                YAxisTitle = 6,
                XAxisMarks = 7,
                YAxisMarks = 8,
                IntermediateLines = 9,
                XScaleFactor = 10,
                YScaleFactor = 11
            }

            public struct DrawAttributes
            {
                public Color AttributeColor;
                public Font AttributeFont;
                public Boolean AttributeEnabled;
                public Double AttribudeWidth;
                public Int32 AttributeQuantity;
                public String AttributeName;                   // для XScaleFactor  и YScaleFactor выступают в роли строки форматирования...
                public Int32 AttributeLength;
                public Double AttributeMultiplyingFactor;      // для проиизвольной линейной калибровки оси x
                public Double AttributeAddingValue;            // для проиизвольной линейной калибровки оси x
            }

            public enum GraphStyle
            {
                Dots = 1,
                Lines = 2,
                Histogram = 3,
                Sectors = 4
            }

            public enum UpperPoints
            {
                UpUp = 1,           // точки с максмальным значением величины по оси ординат будут вверху ((0,0)-левый верхний угол)
                UpDown = 2          // точки с максмальным значением величины по оси ординат будут внизу 
            }

            public class ImagePositioning
            {
                private Double LeftMargin = 0.10;     // Отступы под точки изображения
                private Double RightMargin = 0.10;     // Свободное пространство используется для рисования допю элементов
                private Double TopMargin = 0.10;     // (оси, подписи, промежуточные линии и т.д.)
                private Double BottomMargin = 0.10;     //
                private Double XScaleCoefficient = 1.0;      // Коэффициент масштабирования изображения по горизонтали
                private Double YScaleCoefficient = 1.0;      // Коэффициент масштабирования изображения по вертикали
                private Int32 CanvasHeight = 0;
                private Int32 CanvasWidth = 0;
                private Int32 ControlWidth = 0;
                private Int32 ControlHeight = 0;

                public void SetXScaleCoefficient(Double XScaleCoeff)
                {
                    XScaleCoefficient = XScaleCoeff;
                }

                public Double GetXScaleCoefficient()
                {
                    return XScaleCoefficient;
                }

                public Double GetYScaleCoefficient()
                {
                    return YScaleCoefficient;
                }

                public void SetYScaleCoefficient(Double YScaleCoeff)
                {
                    YScaleCoefficient = YScaleCoeff;
                }

                public Int32 GetRealWidth()
                {
                    if (CanvasWidth > 0 && CanvasHeight > 0)
                        return CanvasWidth;
                    return -1;
                }

                public Int32 GetRealHeight()
                {
                    if (CanvasWidth > 0 && CanvasHeight > 0)
                        return CanvasHeight;
                    return -1;
                }

                public Int32 GetCanvasContainerWidth()
                {
                    if (ControlWidth > 0 && ControlHeight > 0)
                        return ControlWidth;
                    return -1;
                }

                public Int32 GetCanvasContainerHeight()
                {
                    if (ControlWidth > 0 && ControlHeight > 0)
                        return ControlHeight;
                    return -1;
                }

                public void SetCanvasSize(Int32 Width, Int32 Height)
                {
                    ControlWidth = Width;
                    ControlHeight = Height;
                    CalculateCanvasSize();
                }

                private void CalculateCanvasSize()
                {
                    CanvasHeight = (Int32)((Double)ControlHeight * (1.0 - TopMargin - BottomMargin));
                    CanvasWidth = (Int32)((Double)ControlWidth * (1.0 - LeftMargin - RightMargin));
                }


                public Double LeftSpaceLobe
                {
                    get { return LeftMargin; }
                    set { LeftMargin = value; CalculateCanvasSize(); }
                }

                public Double RightSpaceLobe
                {
                    get { return RightMargin; }
                    set { RightMargin = value; CalculateCanvasSize(); }
                }

                public Double TopSpaceLobe
                {
                    get { return TopMargin; }
                    set { TopMargin = value; CalculateCanvasSize(); }
                }

                public Double BottomSpaceLobe
                {
                    get { return BottomMargin; }
                    set { BottomMargin = value; CalculateCanvasSize(); }
                }
            }


            public class GraphDrawer<GraphData>
            {
                private GraphData[] RawData = null;
                private Dictionary<DrawType, DrawAttributes> GraphElements = new Dictionary<DrawType, DrawAttributes>();
                private Point[] GraphPoints = null;
                private Point[] ScaledGraphPoints = null;
                private Boolean PointsCalculated = false;
                private UpperPoints VerticalStyle = UpperPoints.UpUp;
                private ImagePositioning ImagePointsPositioning = new ImagePositioning();

                public GraphDrawer()
                {
                    Int32[] GraphTypes = (Int32[])Enum.GetValues(typeof(DrawType));
                    DrawAttributes DefaultAttributes = new DrawAttributes();
                    foreach (Int32 GraphType in GraphTypes)
                    {
                        DefaultAttributes.AttributeColor = Color.Black;
                        DefaultAttributes.AttributeFont = new Font("Times New Roman", 10.0f);
                        DefaultAttributes.AttributeEnabled = true;
                        DefaultAttributes.AttributeName = String.Empty;
                        DefaultAttributes.AttributeQuantity = 0;
                        DefaultAttributes.AttributeMultiplyingFactor = 1.0;
                        DefaultAttributes.AttributeAddingValue = 0.0;
                        GraphElements[(DrawType)GraphType] = DefaultAttributes;

                    }
                }

                public Boolean Draw(GraphData[] Data, Control CanvasContainer)
                {
                    RawData = null;
                    AssignCanvas(CanvasContainer);
                    PointsCalculated = false;
                    SetDrawingData(Data);
                    Boolean Result = CalculateCoordinates();
                    if (Result) DrawGraph();
                    return Result;
                }

                public Boolean Draw()
                {

                    Boolean Result = (PointsCalculated == true) ? true : CalculateCoordinates();
                    if (Result) DrawGraph();
                    return Result;
                }
                public DrawAttributes GetGraphAttribute(DrawType Type)
                {
                    return GraphElements[Type];
                }

                public void SetGraphAttributeColor(DrawType Type, DrawAttributes NewAttributeValues)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute = NewAttributeValues;
                    GraphElements[Type] = Attribute;
                }

                public void SetGraphAttributeColor(DrawType Type, Color AttributeColor)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttributeColor = AttributeColor;
                    GraphElements[Type] = Attribute;
                }

                public void SetGraphAttributeName(DrawType Type, String Name)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttributeName = Name;
                    GraphElements[Type] = Attribute;
                }

                public void SetGraphAttributeQuantity(DrawType Type, Int32 Quantity)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttributeQuantity = Quantity;
                    GraphElements[Type] = Attribute;
                }

                public void SetGraphAttributeLength(DrawType Type, Int32 Length)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttributeLength = Length;
                    GraphElements[Type] = Attribute;
                }

                public void SetGraphAttributeFont(DrawType Type, Font AttributeFont)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttributeFont = AttributeFont;
                    GraphElements[Type] = Attribute;
                }

                public void SetGraphAttributeWidth(DrawType Type, Double AttributeWidth)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttribudeWidth = AttributeWidth;
                    GraphElements[Type] = Attribute;
                }

                public void SetGraphAttributeMultiplyingFactor(DrawType Type, Double Factor)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttributeMultiplyingFactor = Factor;
                    GraphElements[Type] = Attribute;
                }

                public void SetGraphAttributeAddingValue(DrawType Type, Double Value)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttributeAddingValue = Value;
                    GraphElements[Type] = Attribute;
                }

                public void DisableGraphAttribute(DrawType Type)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttributeEnabled = false;
                    GraphElements[Type] = Attribute;
                }

                public void EnableGraphAttribute(DrawType Type)
                {
                    DrawAttributes Attribute = GraphElements[Type];
                    Attribute.AttributeEnabled = true;
                    GraphElements[Type] = Attribute;
                }

                public void AssignCanvas(Control Canvas)
                {
                    ImagePointsPositioning.SetCanvasSize(Canvas.Width, Canvas.Height);
                    InitImagePoints();
                }

                public void InvertImageVertically()
                {
                    VerticalStyle = VerticalStyle == UpperPoints.UpUp ? UpperPoints.UpDown : UpperPoints.UpUp;
                    InitImagePoints();
                }

                public void InvertImageHorizontally()
                {
                    if (PointsCalculated == true) Points.Reverse();
                }

                public void SetDrawingData(GraphData[] Data)
                {
                    RawData = (GraphData[])Data.Clone();
                    InitImagePoints();
                }

                public void ResetDrawer()
                {
                    RawData = null;
                    ImagePointsPositioning.BottomSpaceLobe = 0.1;
                    ImagePointsPositioning.LeftSpaceLobe = 0.1;
                    ImagePointsPositioning.RightSpaceLobe = 0.1;
                    ImagePointsPositioning.TopSpaceLobe = 0.15;
                }

                private Boolean InitImagePoints()
                {
                    if (RawData != null && RawData.Length > 0)
                    {
                        GraphPoints = new Point[RawData.Length];
                        if (Positioning().GetRealHeight() > 0 && Positioning().GetRealWidth() > 0)
                        {
                            PointsCalculated = CalculateCoordinates();
                            return PointsCalculated;
                        }
                        return false;
                    }
                    return false;
                }

                protected UpperPoints GraphVerticalDrawingStyle
                {
                    get { return this.VerticalStyle; }
                    set { VerticalStyle = value; }       //todo: вычислить координаты снова
                }

                protected virtual Boolean CalculateCoordinates()
                {
                    return false;
                }

                protected virtual void DrawGraph()
                {

                }

                protected virtual void ScaleGraph(Double ScaleX, Double ScaleY, Point Offset)
                {

                }

                protected GraphData[] GraphSource
                {
                    get { return RawData; }
                }

                public ImagePositioning Positioning()
                {
                    return ImagePointsPositioning;
                }

                protected Point[] Points
                {
                    get { return GraphPoints; }
                    set { GraphPoints = value; }
                }

                protected Point[] GraphicPoints(Boolean Scaled)
                {
                    return Scaled == true ? ScaledGraphPoints : GraphPoints;
                }
            }
        }
    }
}
